#ifndef __SYSTEMS__RES_MANAGER__HPP__
# define __SYSTEMS__RES_MANAGER__HPP__

# include "misc/errors.hpp"
# include "system.hpp"

# include <boost/shared_ptr.hpp>
# include <boost/noncopyable.hpp>
# include <boost/foreach.hpp>
# include <boost/any.hpp>

# include <string>
# include <sstream>
# include <vector>
# include <map>

class res_manager_t : private boost::noncopyable, public if_system_t
{
public:

    static boost::shared_ptr<if_system_t> create(f_engine_t *engine);

    void start(); /*override*/

    void add_res_location(const std::string& location);

    template<typename T>
    boost::shared_ptr<T> get_res(const std::string &name);

    void free_res(const std::string &name);

    bool is_loaded(const std::string &name);

private:
    res_manager_t(f_engine_t *engine) :
        engine_(engine)
    {
    }

    boost::shared_ptr<std::stringstream> make_stream(const std::string &file_path);

    typedef std::map<std::string, boost::any> res_map_t;

    std::vector<std::string> res_locations_;

    res_map_t loaded_resources_;

    f_engine_t *engine_;
};

template<typename T>
boost::shared_ptr<T> res_manager_t::get_res(const std::string &name)
{

    //search in loaded resources
    res_map_t::const_iterator it = loaded_resources_.find(name);
    if (it != loaded_resources_.end())
    {
        return boost::any_cast<boost::shared_ptr<T> >(it->second);
    }

    //load new resource
    boost::shared_ptr<std::stringstream> stream;

    BOOST_FOREACH( const std::string &location, res_locations_)
                {
                    stream = make_stream(location + name);
                    if (stream)
                    {
                        boost::shared_ptr<T> ret(T::create(stream));
                        loaded_resources_[name] = ret;
                        return ret;
                    }
                }

    throw std::runtime_error(std::string("can't find resource ") + name);
}

#endif //__SYSTEMS__RES_MANAGER__HPP__
